package cn.layfolk.seckill.web.controller;


import cn.layfolk.daimao.consts.ErrorCodeEnum;
import cn.layfolk.daimao.consts.MQConstans;
import cn.layfolk.daimao.exception.MessageCenterException;
import cn.layfolk.daimao.vo.TUser;
import cn.layfolk.daimao.vo.respvo.ResponseVo;
import cn.layfolk.seckill.domain.TOrderInfo;
import cn.layfolk.seckill.mq.msg.CreateOrderMessage;
import cn.layfolk.seckill.redis.SeckillRedisKey;
import cn.layfolk.seckill.service.TOrderInfoService;
import cn.layfolk.seckill.service.TSeckillGoodsService;
import cn.layfolk.seckill.service.TSeckillOrderService;
import cn.layfolk.seckill.vo.SeckillGoodsVo;
import cn.layfolk.seckill.vo.reqvo.SeckillReqVo;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@RestController
@RequestMapping("/orders")
@Valid
public class TOrderInfoController {


    @Autowired
    private TSeckillGoodsService seckillGoodsService;

    @Autowired
    private TSeckillOrderService seckillOrderService;

    @Autowired
    private TOrderInfoService orderInfoService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public static final Map<Long,Boolean> STOCK_OVER_FLAG = new ConcurrentHashMap<>(20);


    /**
     * 获取订单信息
     */
    @GetMapping("/{orderNo}")
    public ResponseVo<TOrderInfo> findById(@PathVariable("orderNo") String orderNo){
        return ResponseVo.ok(orderInfoService.findById(orderNo));
    }


    /**
     * 开始秒杀
     */
    @PostMapping("/{random}/seckill")
    public ResponseVo<?> doSeckill(SeckillReqVo seckillReqVo,
            @PathVariable("random") @NotNull(message = "秒杀参数错误") String random){
        //获取当前用户
        TUser user = null;

        if (user == null){
            throw new MessageCenterException(ErrorCodeEnum.USER_NOT_LOGIN);
        }

        // 秒杀路径是否有效
        String oldRandom  = (String) stringRedisTemplate.opsForHash().get(SeckillRedisKey.SECKILL_PATH_HASH.getRealKey(seckillReqVo.getSeckillId()+""),user.getId()+"");
        if (StringUtils.isEmpty(oldRandom) || !random.equals(oldRandom)){
            //无效
            throw new MessageCenterException(ErrorCodeEnum.OP_ERROR);
        }

        // 判断本地标识，该秒杀商品是否已经售卖完
        Boolean stockOver = STOCK_OVER_FLAG.get(seckillReqVo.getSeckillId());
        if (stockOver != null && stockOver){
            throw new MessageCenterException(ErrorCodeEnum.OUT_OF_STOCK_ERROR);
        }

        //1.先获取秒杀商品信息
        SeckillGoodsVo vo = seckillGoodsService.findByIdInCache(seckillReqVo.getSeckillId());
        if (vo==null){
            throw new MessageCenterException(ErrorCodeEnum.OP_ERROR);
        }
        //2.判断当前时间是否在秒杀活动范围内
        Date now = new Date();
        //当前时间大于等于开始时间 and 小于等于结束时间
        if (now.compareTo(vo.getStartDate())<0){
            throw new MessageCenterException(ErrorCodeEnum.SECKILL_NOT_STARTED);
        }

        if (now.compareTo(vo.getEndDate())>0){
            throw new MessageCenterException(ErrorCodeEnum.SECKILL_IS_STOP);
        }
        //3. 判断用户是否是已经对该对象秒杀活动下过单
        //SeckillOrder seckillOrder = seckillOrderService.findByUserIdAndSeckillId(user.getId(),seckillId);
        Boolean member = stringRedisTemplate.opsForSet().isMember(
                SeckillRedisKey.SECKILL_ORDER_SET.getRealKey(seckillReqVo.getSeckillId() + ""), user.getId() + "");
        if (member == null|| member){
            throw new MessageCenterException(ErrorCodeEnum.REPEATE_ORDEER_ERROR);
        }

        //4. 判断秒杀商品库存是否充足
        //使用Redis对库存进行预减，之后基于redis库存的判断，都在redis中进行
        Long stock = stringRedisTemplate.opsForHash().increment(SeckillRedisKey.SECKILL_STOCK_COUNT_HASH.getRealKey(""),
                vo.getId()+"", -1);
        //当最后一个库存减完以后，库存还剩0，当其他没有库存的线程过来时，直接再减库存机会变为负数
        if (stock < 0){
            // 标记对应的商品售卖完了
            STOCK_OVER_FLAG.put(seckillReqVo.getSeckillId(), true);
            throw new MessageCenterException(ErrorCodeEnum.OUT_OF_STOCK_ERROR);
        }

      /*  if (vo.getStockCount()<1){
            throw new MessageCenterException(ErrorCodeEnum.OUT_OF_STOCK_ERROR);
        }*/
        //5.基础校验通过以后，开始创建秒杀订单
        //String orderNo = orderInfoService.doSeckill(vo,user.getId());
        // 修改为使用 RockeyMQ 发送创建订单的消息
        rocketMQTemplate.syncSend(MQConstans.CREATE_SECKILL_ORDER_DEST, new CreateOrderMessage(vo.getId(),user.getId(),seckillReqVo.getUuid()));
        return ResponseVo.ok("正在排队中，请耐心等待");
    }


}

